package com.stud.common.filter;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.filter.ValueFilter;
import com.stud.common.constant.Constants;
import com.stud.common.utils.StringUtils;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * 自定义TrimRequestWrapper类
 *
 * @author Stud
 * @date 2023-02-02 12:21:06
 */
@Slf4j
public class TrimRequestWrapper extends HttpServletRequestWrapper {

    /**
     * 保存处理后的参数
     */
    private final Map<String, String[]> params = new HashMap<>();


    public TrimRequestWrapper(HttpServletRequest request) {
        //将request交给父类，以便于调用对应方法的时候，将其输出
        super(request);

//        Enumeration<String> headerNames = request.getHeaderNames();
//        while (headerNames.hasMoreElements()) {
//            String s = headerNames.nextElement();
//            log.info(s + "==" + request.getHeader(s));
//        }

        setParams(request);
    }

    private void setParams(HttpServletRequest request) {
        if (request != null) {
            try {
                request.setCharacterEncoding(Constants.UTF8);
            } catch (UnsupportedEncodingException ignored) {
            }
        }
        Map<String, String[]> requestMap = request.getParameterMap();
        requestMap.forEach((key, values) -> {
            if (Objects.nonNull(values[0])) {
                values[0] = values[0].trim();
            }
            params.put(key, values);
        });
    }

    /**
     * 重写getParameter 参数从当前类中的map获取
     */
    @Override
    public String getParameter(String name) {
        String[] values = params.get(name);
        if (values == null || values.length == 0) {
            return null;
        }
        return values[0];
    }

    /**
     * 重写getParameterValues
     */
    @Override
    public String[] getParameterValues(String name) {//同上
        return params.get(name);
    }

    /**
     * 重写getParameterMap
     */
    @Override
    public Map<String, String[]> getParameterMap() {//同上
        return params;
    }

    /**
     * 重写getInputStream方法  post类型的请求参数必须通过流才能获取到值
     * 这种获取的参数的方式针对于内容类型为文本类型，比如Content-Type:text/plain,application/json,text/html等 在springmvc中可以使用@RequestBody 来获取
     * json数据类型 其他文本类型不做处理，重点处理json数据格式 getInputStream() ，只有当方法为post请求，且参数为json格式是，会被默认调用
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
        String body = IOUtils.toString(super.getInputStream(), StandardCharsets.UTF_8);
        if (StringUtils.isEmpty(body)) {
            return super.getInputStream();
        }
        JSONObject json = JSON.parseObject(body);
        String newBody = JSON.toJSONString(json, new TrimValueFilter());
        ByteArrayInputStream bis = new ByteArrayInputStream(newBody.getBytes(StandardCharsets.UTF_8));
        return new MyServletInputStream(bis);
    }

    private static class TrimValueFilter implements ValueFilter {
        @Override
        public Object apply(Object object, String name, Object value) {
            if (value instanceof String) {
                value = StringUtils.trim((String) value);
            }
            return value;
        }
    }

    private static class MyServletInputStream extends ServletInputStream {
        private final ByteArrayInputStream bis;

        public MyServletInputStream(ByteArrayInputStream bis) {
            this.bis = bis;
        }

        @Override
        public boolean isFinished() {
            return true;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {

        }

        @Override
        public int read() {
            return bis.read();
        }
    }

}
